package main

import (
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	"gitee.com/sillyman/mixlog"
	"github.com/PuerkitoBio/goquery"
	"github.com/pkg/errors"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"

	"gitee.com/sillyman/WebCrawler/htmlParser"
	"gitee.com/sillyman/WebCrawler/requester"
	"gitee.com/sillyman/WebCrawler/urlqueue"
)

// bookfereEssays 书伴网的精选短文
type bookfereEssays struct {
	Id          int64
	CreatedAt   time.Time
	PublishedAt time.Time // 发布日期
	Title       string    `gorm:"VARCHAR(255)"` // 文章标题
	Content     string    `gorm:"MEDIUMTEXT"`   // 文章内容，HTML文本
	URL         string    `gorm:"VARCHAR(255)"` // 短文URL
}

// 初始化ORM
func initORM() (*gorm.DB, error) {
	dsn := "bookfere_admin:12345678@tcp(127.0.0.1:3306)/bookfere?parseTime=true" // 使用MySQL时必须带参数`parseTime=true`，否则会报错
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
		Logger: logger.New(
			log.New(os.Stdout, "", log.LstdFlags),
			logger.Config{
				SlowThreshold: time.Second, // 慢 SQL 阈值
				Colorful:      true,        // 彩色打印
				LogLevel:      logger.Warn, // Log level
			},
		),
	})
	if err != nil {
		return nil, errors.Wrap(err, "打开数据库连接失败")
	}

	return db, db.AutoMigrate(new(bookfereEssays))
}

// 处理HTTP应答
func generateOnResponseHandle(db *gorm.DB, q urlqueue.URLQueue) requester.ResponseHook {
	return func(URL *url.URL, statusCode int, contentType string, body io.Reader, header http.Header, cookies []*http.Cookie) {
		// 只处理 HTML 页面
		if statusCode != 200 && contentType != "text/html" {
			return
		}

		doc, err := htmlParser.NewDocumentFromReader(body)
		if err != nil {
			mixlog.Warningf("页面 %s 无法被解析：%s", URL.String(), err.Error())
			return
		}
		mainSelector := doc.Find("#main")

		// 抽取分页URL
		htmlParser.WalkALinks(mainSelector, ".page-numbers", func(element *goquery.Selection) bool {
			link, ok := element.Attr("href")
			if ok {
				err := q.Push(link, URL.String())
				if err != nil {
					mixlog.Errorf("压入 %s 到列队：%s", link, err.Error())
				}
				mixlog.Infof("已经压入 %s 到列队", link)
			}
			return true
		})

		// 抽取文章URL
		htmlParser.WalkElement(mainSelector, ".entry-title", func(element *goquery.Selection) bool {
			link, ok := element.Find("a").First().Attr("href")
			if ok {
				err := q.Push(link, URL.String())
				if err != nil {
					mixlog.Errorf("压入 %s 到列队：%s", link, err.Error())
				}
				mixlog.Infof("已经压入 %s 到列队", link)
			}
			return true
		})

		// 获取文章内容
		if strings.EqualFold(URL.Host, "bookfere.com") {
			if pth := strings.ToLower(URL.Path); strings.HasPrefix(pth, "/post/") && strings.HasSuffix(pth, ".html") {
				title := htmlParser.GetText(mainSelector, "h1.entry-title")

				e1 := htmlParser.GetElement(mainSelector, "time.published")
				publishedAt, _ := time.Parse("2006-01-02T15:04:05-07:00", e1.AttrOr("datetime", ""))

				e2 := htmlParser.GetElement(mainSelector, "div.entry-content")
				e2.Find(".con-top").First().Remove() // 踢出广告代码
				contentHTML, err := e2.Html()
				if err != nil {
					mixlog.Warningf("不能解析 %s 的文章内容：%s", URL.Path, err.Error())
				}

				result := db.Create(&bookfereEssays{
					Title:       title,
					PublishedAt: publishedAt,
					Content:     contentHTML,
					URL:         URL.String(),
				})
				if err := result.Error; err != nil {
					mixlog.Errorf("插入 %s 文章内容到数据库：", URL.Path, err.Error())
				}
				mixlog.Infof("已经获取 %s 的文章内容", URL.Path)
			}
		}
	}
}
